En el presente estudio se procederá a analizar el data set llamado “Netflix Prize data” obtenido en la página web Kaggle. Dicho dataset se creó como una competición para encontrar el mejor algoritmo de predicción de la puntuación que los usuarios dan a las películas de la plataforma.
Antes de extraer la información y comenzar a trabajar sobre ella se ha procedido a visualizar a qué tipo de datos íbamos a enfrentarnos. El dataset contiene diversos archivos pero solo nos centraremos con los que vamos a trabajar en este estudio:
Los archivos ‘combined_data_{nº}’ contienen la información de las puntuaciones de los usuarios para determinado código de película, así como el identificador de usuario y la fecha (día, mes y año) en la que se dio dicha valoración.
Esta base de datos cuenta con un tamaño de espacio en memoria demasiado elevado, por lo que se procederá a extraer una parte de los datos y nos quedaremos con las 100 primeras películas de cada archivo.
Otro de los archivos que se utilizarán en este estudio contiene el título de cada ID asociado a las películas además del año en el que se estrenó. En secciones posteriores explicaremos como realizaremos la inclusión de estos datos junto con los datos iniciales para obtener el dataset final para trabajar más comodamente.
Una vez realizado este proceso, pensamos en generar nuevas variables para incluirlas en nuestro estudio ya que sería interesante medir la diferencia de años transcurridos desde el estreno hasta la puntuación de las diferentes películas (“YearsSinceRelease”).
TODO: Comentar…
Función
#Función que obtiene los datos de filas específicas
obtain_movies = function(combined_data, idx){
#Obtenemos las películas del archivo a leer (1,2,3 o 4)
rows_data = filter(filas_ID_combined_all, data == idx)
rows_data = select(rows_data, fila, fila_final)
#Por cada fila guardamos el rango de posiciones a leer en el fichero
ranges = c()
for(i in 1:nrow(rows_data)){
ranges = c(ranges, rows_data[[i,1]]:rows_data[[i,2]])
}
#Nos quedamos solo con los datos de las películas de la muestra
combined_data = slice(combined_data, ranges)
return(combined_data)
}
Lectura de los ficheros y creación del fichero único con las películas de la muestra
#Leemos el índice
filas_ID_combined_all = read_csv("data/filas_ID_combined_all.txt")
#Cargamos los ficheros con la información de Netflix
combined_data1 = read_tsv("data/combined_data_1.txt", col_names=FALSE)
combined_data2 = read_tsv("data/combined_data_2.txt", col_names=FALSE)
combined_data3 = read_tsv("data/combined_data_3.txt", col_names=FALSE)
combined_data4 = read_tsv("data/combined_data_4.txt", col_names=FALSE)
#Obtenemos nuestra muestra de películas
n_muestra = 250
set.seed(2495)
muestra_grupo = sample(1:17770, n_muestra, replace = FALSE)
#Nos quedamos con el índice de las películas de nuestra muestra
filas_ID_combined_all = filter(filas_ID_combined_all, filas_ID_combined_all$ID %in% muestra_grupo)
filas_ID_combined_all = select(filas_ID_combined_all, ID, fila, fila_final, data)
#Mostramos cuántas películas debemos leer de cada fichero
#table(filas_ID_combined_all$data)
#Leemos las observaciones de las películas de nuestra muestra
data1 = obtain_movies(combined_data1, 1)
data2 = obtain_movies(combined_data2, 2)
data3 = obtain_movies(combined_data3, 3)
data4 = obtain_movies(combined_data4, 4)
#Juntamos los datos de las películas de los 4 ficheros
df_ratings = rbind(data1,data2,data3,data4)
#Exportamos los datos de las películas de nuestra muestra
write.table(df_ratings,"data/combined_data_sample.txt", row.names = FALSE, col.names = FALSE)
#Eliminamos variables que ya no son útiles
rm(combined_data1, combined_data2, combined_data3, combined_data4, data1, data2, data3, data4, filas_ID_combined_all)
TODO: Comentar…
#Se asigna una posición a cada observación para posteriormente indicar el id de película de cada una de ellas
df_ratings = df_ratings %>%
mutate(Idx = row_number())
#Guardamos la fila donde empieza cada película
movie_rows = grep(":", df_ratings$X1)
#Añadimos el id de la película a cada posición y eliminamos el caracter ":"
rows_ID = df_ratings %>%
filter(Idx %in% movie_rows) %>%
mutate(X1 = as.integer(gsub(":","",X1)))
#Número de veces que se tendrá que repetir el identificador de cada película
reps = diff(c(rows_ID$Idx, max(df_ratings$Idx) + 1))
netflix = df_ratings %>%
mutate(MovieID = rep(rows_ID$X1, times = reps)) %>%
filter(!(Idx %in% rows_ID))
#Se definen las columnas del dataframe
netflix = netflix %>%
separate(X1,into = c("UserID","Rating","RatingDate"), sep = ",") %>%
na.omit(netflix) %>%
mutate(Idx = row_number())
#Se eliminan las variables auxiliares
rm(df_ratings, movie_rows, rows_ID, reps)
Lectura del fichero movies_titles.csv
df_movies = read_tsv("data/movie_titles.csv", locale = readr::locale(encoding = "ISO-8859-1"), col_names=FALSE)
df_movies = df_movies %>%
separate(X1,",",into =c("MovieID","MovieRelease","Title"), extra="merge")
#Se transforma la variable MovieRelease a numérica
netflix$MovieID = as.character(netflix$MovieID)
#Se unifica el dataframe de las puntuaciones con el de las películas
netflix = inner_join(x = netflix, y = df_movies, by = "MovieID", all = TRUE)
#Se transforma la variable 'Rating' a tipo númerica
netflix$Rating = as.numeric(netflix$Rating)
#Se transforma la variable 'RatingDate' a tipo date
netflix$RatingDate = as.Date(netflix$RatingDate, format = "%Y-%m-%d")
#Se transforma la variable MovieRelease a numérica
netflix$MovieRelease = as.numeric(netflix$MovieRelease)
#Se añade la diferencia en años entre el año de puntuación y el de estreno de la película
netflix = mutate(netflix, YearsSinceRelease = year(RatingDate) - MovieRelease)
#Se transforma la variable YearsSinceRelease a numérica
netflix$YearsSinceRelease = as.numeric(netflix$YearsSinceRelease)
#Adicionalmente, dividimos la variable RatingDate en: día, mes y año
sep = netflix %>%
separate(RatingDate,into = c("Year","Month","Day"), sep = "-") %>%
na.omit(netflix) %>%
mutate(Idx = row_number())
netflix = mutate(netflix, sep)
rm(sep)
#Se ordenan las posiciones de las columnas y se indican su nuevo nombre
netflix = select(netflix, Idx, MovieID, Title, UserID, Rating, Day, Month, Year, RatingDate, MovieRelease, YearsSinceRelease)
#Exportamos el fichero preparado y construido para empezar a trabajar en su análisis
write.csv(netflix, "data/netflix.csv", row.names = FALSE)
str(netflix)
## tibble [1,093,856 x 11] (S3: tbl_df/tbl/data.frame)
## $ Idx : int [1:1093856] 1 2 3 4 5 6 7 8 9 10 ...
## $ MovieID : chr [1:1093856] "43" "43" "43" "43" ...
## $ Title : chr [1:1093856] "Silent Service" "Silent Service" "Silent Service" "Silent Service" ...
## $ UserID : chr [1:1093856] "305151" "497196" "2327803" "2625420" ...
## $ Rating : num [1:1093856] 4 3 1 2 5 2 1 3 5 2 ...
## $ Day : chr [1:1093856] "20" "13" "19" "13" ...
## $ Month : chr [1:1093856] "02" "04" "08" "05" ...
## $ Year : chr [1:1093856] "2005" "2003" "2001" "2004" ...
## $ RatingDate : Date[1:1093856], format: "2005-02-20" "2003-04-13" ...
## $ MovieRelease : num [1:1093856] 2000 2000 2000 2000 2000 2000 2000 2000 2000 2000 ...
## $ YearsSinceRelease: num [1:1093856] 5 3 1 4 3 3 5 2 3 3 ...
## - attr(*, "na.action")= 'omit' Named int [1:250] 1 107 293 1390 3766 4458 5563 5738 8145 8489 ...
## ..- attr(*, "names")= chr [1:250] "1" "107" "293" "1390" ...
Idx: Variable numérica que determina la posición o índice de cada observación del dataset.
MovieID: Variable numérica que identifica a cada película con un ID determinado, este ID está asociado a un título que será representado por la variable “Title”.
Title: Variable con datos definidos como caracteres. Esta variable representa el título de cada una de las películas identificadas con un ID en la variable “MovieID”.
UserID: Variable con datos definidos como caracteres que representa el ID único del usuario que ha calificado cada película.
Rating: Variable categórica que representa la calificación que ha hecho cada usuario de las películas que ha puntuado. Esta calificación puede ser dentro del rango [1,2,3,4,5], donde 1 estrella representa la calificación más baja y 5 estrellas la calificación más alta.
RatingDate: Variable definida como tipo **date*, que representa la fecha en la cual el usuario realizó la calificación de una determinada película.
MovieRelease: Variable numérica que indica el año en el cual se estrenó la película. El año de estreno puede referirse tanto a estreno de una determinada película en el cine como en DVD.
YearsSinceRelease: Variable numérica la cual se ha calculado mediante la resta de RatingDate y MovieRelease. Esta variable indica el número de años que ha pasado desde que se ha estrenado una determinada película hasta que el usuario la ha calificado.
import pandas as pd
netflix_py = pd.read_csv("data/netflix.csv")
res = pd.concat([netflix_py.groupby('MovieID')['Rating'].describe(),
netflix_py.groupby('MovieID')['Rating'].agg(pd.Series.mode).rename('mode'),
netflix_py.groupby('MovieID')['Rating'].agg(pd.Series.median).rename('median')
], axis=1).T
print(res)
## MovieID 43 195 ... 17606 17751
## count 105.000000 185.000000 ... 87.000000 2475.000000
## mean 2.571429 3.297297 ... 2.229885 3.938182
## std 1.284951 1.039044 ... 1.075100 1.133302
## min 1.000000 1.000000 ... 1.000000 1.000000
## 25% 1.000000 3.000000 ... 1.000000 3.000000
## 50% 3.000000 3.000000 ... 2.000000 4.000000
## 75% 3.000000 4.000000 ... 3.000000 5.000000
## max 5.000000 5.000000 ... 5.000000 5.000000
## mode 3.000000 3.000000 ... 1.000000 5.000000
## median 3.000000 3.000000 ... 2.000000 4.000000
##
## [10 rows x 250 columns]
movies_table = table(netflix$MovieID)
#Ordenamos las MovieID en función del número de calificaciones y de forma descendente:
orden = sort(movies_table, decreasing = TRUE)
#Pedimos que nos imprima las 5 primeras observaciones, para obtener asi las 5 películas más votadas:
head(orden, 5)
##
## 6408 2580 3610 2186 11663
## 82949 80136 75148 61174 54845
#Una vez sabemos el MovieID de las películas más votadas las filtramos:
mas_votadas = filter(netflix, MovieID == c("6408","2580","3610","2186","11663"))
## Warning in MovieID == c("6408", "2580", "3610", "2186", "11663"): longitud de
## objeto mayor no es múltiplo de la longitud de uno menor
mas_votadas = as.data.frame(mas_votadas)
#Representamos
boxplot = ggplot(mas_votadas,aes(Title, Rating, group=MovieID))+
geom_boxplot(fill = "darkseagreen1", colour = "black", outlier.colour = "darkgreen")+
geom_point(stat= "summary", shape=20, size=2, color="red")
ggplotly(boxplot)
## No summary function supplied, defaulting to `mean_se()`
## Warning: `group_by_()` is deprecated as of dplyr 0.7.0.
## Please use `group_by()` instead.
## See vignette('programming') for more help
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_warnings()` to see where this warning was generated.
#Compara sus estadísticos y distribuciones(histogramas, boxplot, violin plot,. . . )
## Distribución de valoraciones por día
## Distribución de valoraciones por mes
```r
#Investiga la distribución de valoraciones por día de la semana y por mes.¿Qué meses y días de la semana se valoran más películas en netflix?
#Tabla agrupada por película y año del número de valoraciones.
#Representación gráfica.
#Distribución del score promedio por año.
Analizar número de votaciones de las diferentes películas. ¿Cuántas películas hay de cada rating (1,2,3,4 y 5 estrellas)?
ggplot(data = netflix, aes(x = Rating)) +
geom_bar(aes(y = ..count.., fill = ..count..),
stat="count",
show.legend = FALSE) +
geom_label(aes(label = ..count.., y = ..count..),
stat = "count",
vjust = -.5) +
scale_fill_gradient(low = "lightcoral", high = "firebrick2")+
labs(x = "Rating", y = "Number of ratings", title = "Total Ratings")+
scale_y_continuous(limits=c(0,380000), labels = scales::comma)+
coord_flip() +
theme_classic()
# Image in the visualization
image = image_read("imgs/icon-rating.png")
grid.raster(image, x = 0.80, y = 0.25, height = 0.23)
media = mean(netflix$Rating, na.rm = TRUE)
media
## [1] 3.560383
moda = names(which(table(netflix$Rating) == max(table(netflix$Rating))))
moda
## [1] "4"
Como se puede observar en el gráfico, las puntuaciones generalmente han sido positivas ya que la mayoria de los casos tienen una puntuación superior a 3.
La calificación de 4 que ha sido dada por un total de 2926 usuarios, es la que se ha dado más veces.
La calificación media de todas las películas es de 3.37.
#Comentar con Camila
netflix %>%
count(YearsSinceRelease, Rating) %>%
ggplot(mapping = aes(x = YearsSinceRelease, y = Rating))+
geom_tile(mapping = aes(fill = n))
#Más votada
df_more_voted = netflix[netflix$MovieID == names(which.max(movies_table)),]
ggplot(data = df_more_voted, aes(x = Rating)) +
geom_bar(aes(y = ..count.., fill = ..count..),
stat="count",
show.legend = FALSE) +
geom_label(aes(label = ..count.., y = ..count..),
stat = "count",
vjust = -.5) +
scale_fill_gradient(low = "cadetblue1", high = "cadetblue4")+
labs(x = "Rating", y = "Number of ratings", title = df_more_voted$Title[1])+
scale_y_continuous(limits=c(0,45000))+
coord_flip() +
theme_classic()
#Image in the visualization
image = image_read("imgs/masvotada.jpg")
grid.raster(image, x = 0.80, y = 0.35, height = 0.4)
#Menos votada
df_less_voted = netflix[netflix$MovieID == names(which.min(movies_table)),]
ggplot(data = df_less_voted, aes(x = Rating)) +
geom_bar(aes(y = ..count.., fill = ..count..),
stat="count",
show.legend = FALSE) +
geom_label(aes(label = ..count.., y = ..count..),
stat = "count",
vjust = -.5) +
scale_fill_gradient(low = "darkgoldenrod1", high = "darkgoldenrod3")+
labs(x = "Rating", y = "Number of ratings", title = df_less_voted$Title[1])+
scale_y_continuous(limits=c(0,8))+
coord_flip() +
theme_classic()
# Image in the visualization
image = image_read("imgs/menosvotada.jpg")
grid.raster(image, x = 0.80, y = 0.35, height = 0.4)
calif = table(netflix$MovieID, netflix$Rating)
calif
##
## 1 2 3 4 5
## 10003 32 21 35 10 9
## 10068 39 19 66 83 118
## 10119 360 1238 4354 3870 1454
## 10143 401 985 4316 5922 4713
## 10238 24 36 40 16 12
## 10272 120 117 518 864 818
## 10337 838 2481 5554 3349 932
## 10355 25 33 27 6 3
## 10476 66 107 310 435 423
## 10546 21 17 25 5 1
## 10705 28 22 27 7 5
## 10706 13 22 23 14 9
## 10811 32 11 72 100 92
## 10813 13 4 26 55 20
## 10873 47 125 124 32 6
## 10878 11 16 38 45 31
## 10887 38 109 395 348 160
## 1093 26 27 33 14 10
## 10957 45 101 388 356 153
## 11070 141 195 345 209 123
## 11076 79 169 323 196 88
## 11116 13 28 56 27 22
## 11380 9 25 48 11 6
## 11482 46 65 106 90 38
## 11532 99 184 380 194 75
## 11577 70 160 539 375 124
## 11624 35 50 72 34 23
## 11635 48 55 221 331 202
## 11663 2024 6381 18680 18417 9343
## 11722 391 979 3105 4332 1933
## 11808 41 43 35 7 11
## 11826 85 249 426 251 123
## 12015 740 3066 10313 7340 2271
## 12091 258 278 589 437 425
## 12197 110 163 224 113 41
## 12449 52 44 49 13 11
## 12499 101 296 537 219 45
## 12518 97 202 338 155 56
## 12519 17 30 42 19 12
## 12607 30 50 205 240 121
## 12634 24 10 78 158 86
## 1271 15 22 124 166 86
## 13117 21 26 64 23 24
## 13131 14 17 32 29 13
## 13137 64 66 89 31 13
## 13227 764 1173 2770 2274 1311
## 13243 37 28 41 27 18
## 13609 42 47 174 115 56
## 13617 12 10 22 46 16
## 13619 192 152 348 236 208
## 13632 19 35 88 29 14
## 13644 325 727 1133 557 121
## 13645 72 186 463 315 187
## 13704 34 15 108 169 151
## 13768 7 15 45 61 38
## 13878 59 47 157 228 380
## 13969 31 22 46 41 31
## 14010 256 740 2183 2247 966
## 14037 31 20 76 103 110
## 14080 318 520 955 598 340
## 14231 31 35 52 45 21
## 14267 18 20 35 20 33
## 14286 11 14 26 27 20
## 14333 50 49 38 14 10
## 14342 387 1079 3707 5367 3205
## 14557 25 19 92 167 207
## 14615 10 7 29 67 40
## 14742 281 263 1142 3385 5042
## 14785 47 63 59 19 6
## 14905 76 57 256 589 611
## 15078 795 2986 9688 9464 4715
## 15115 25 49 103 60 30
## 15195 54 15 65 118 211
## 15258 19 15 37 47 20
## 15347 30 77 235 166 72
## 15620 77 86 59 22 9
## 15655 15 15 35 31 23
## 16084 60 64 65 14 12
## 16101 29 18 61 37 21
## 16145 35 33 26 12 4
## 16162 126 135 579 640 413
## 16227 26 25 41 20 17
## 1627 68 230 1271 1940 1034
## 16354 0 0 13 16 14
## 16365 296 495 1347 1464 1067
## 16379 495 575 402 159 63
## 16414 28 40 98 76 35
## 16465 1594 4435 11946 12777 7650
## 16494 96 83 216 116 94
## 16540 19 57 112 77 52
## 16546 38 86 401 298 90
## 16548 350 370 1061 1049 922
## 16566 37 18 72 91 185
## 16598 14 19 32 31 7
## 16654 23 33 99 37 19
## 16817 23 10 31 16 14
## 16839 16 27 72 32 12
## 16891 454 1744 5435 5722 3484
## 17180 457 1949 5453 3877 1543
## 17300 83 47 21 4 3
## 17325 16 11 32 44 36
## 17363 35 26 88 73 74
## 17454 67 117 250 168 67
## 17526 436 1431 7274 13072 10568
## 17553 16 24 28 9 4
## 17578 149 710 3094 3119 840
## 17606 28 23 26 8 2
## 17751 147 125 413 839 951
## 1888 29 36 21 13 7
## 195 13 21 69 62 20
## 2017 54 193 623 568 324
## 2041 19 14 21 38 21
## 206 54 71 229 364 378
## 2186 1650 4672 17565 22807 14480
## 2234 17 21 45 71 80
## 2259 38 18 110 279 245
## 2279 109 202 626 485 332
## 2299 24 14 179 413 412
## 2325 26 22 142 202 122
## 2424 60 63 229 436 286
## 2434 14 20 40 29 15
## 2442 24 35 103 73 76
## 2528 434 1464 4156 2772 1000
## 2580 2451 7037 27506 30128 13014
## 2691 9 13 85 224 217
## 2770 21 28 66 64 48
## 2923 93 95 52 11 11
## 2967 216 442 827 503 158
## 2992 829 3314 14383 17683 8086
## 3002 14 27 56 45 14
## 3025 47 44 169 320 359
## 3125 28 53 170 192 80
## 3140 36 22 27 14 14
## 3174 891 1999 2812 1212 398
## 3203 25 22 34 11 6
## 3288 24 29 110 105 130
## 3373 36 50 106 103 41
## 3386 41 85 111 50 25
## 3447 27 36 33 11 3
## 3448 22 26 41 21 10
## 3480 65 238 1018 1247 325
## 3510 273 858 2708 2980 969
## 3516 20 6 12 15 25
## 3521 488 496 947 2109 3227
## 3552 76 61 48 20 14
## 3610 1628 4819 19745 28681 20275
## 3629 22 50 89 41 12
## 3744 19 26 72 43 24
## 3758 946 1425 2154 1533 637
## 3790 8 7 17 13 12
## 3823 28 56 124 54 31
## 3885 31 61 146 90 56
## 4242 18 25 123 99 32
## 4254 155 138 312 261 441
## 4297 22 27 43 13 9
## 43 29 21 31 14 10
## 4318 27 22 31 20 15
## 4337 34 77 139 76 46
## 4358 38 52 88 36 28
## 4396 399 690 1610 1047 450
## 4416 35 56 88 59 35
## 4451 45 51 106 59 40
## 4486 37 40 58 33 25
## 4565 101 368 1788 2828 894
## 4658 137 169 1025 2543 1867
## 4747 140 170 260 261 165
## 4908 12 17 56 46 27
## 5028 27 48 71 34 16
## 5039 17 43 72 19 9
## 505 127 408 1036 614 190
## 5064 116 141 296 343 224
## 5066 115 162 449 530 369
## 5128 38 26 130 142 101
## 5182 134 268 340 174 88
## 5193 18 27 18 6 4
## 5751 1002 1408 2022 1294 676
## 5810 39 16 35 78 137
## 5842 105 209 803 805 330
## 5896 147 192 555 546 434
## 6007 735 719 1731 4394 11779
## 6060 2149 6051 13667 8454 2158
## 6075 11 16 50 88 53
## 6143 18 25 50 28 20
## 6211 23 77 240 156 43
## 6219 375 1307 4496 5921 2990
## 6228 83 117 349 428 307
## 6256 4 1 3 1 1
## 6293 34 46 30 5 6
## 6335 37 94 200 111 50
## 6381 65 97 85 24 6
## 6408 989 4216 21690 35260 20794
## 647 50 66 246 190 139
## 6540 33 35 73 51 54
## 6544 87 170 319 267 180
## 6617 21 51 96 34 9
## 6635 147 278 836 1191 858
## 667 48 71 280 369 336
## 6684 11 18 50 25 8
## 684 26 52 67 22 7
## 6852 47 127 331 241 102
## 693 268 440 884 519 295
## 7029 79 110 73 24 18
## 7085 49 45 127 110 94
## 7127 303 967 3304 4547 2478
## 721 60 120 114 35 14
## 7335 16 19 59 61 24
## 7452 91 110 103 36 25
## 7519 24 71 196 181 60
## 7552 56 137 642 747 343
## 7626 15 17 38 24 20
## 7710 64 97 277 299 150
## 7739 1166 3038 5134 2675 737
## 7749 247 194 580 1816 4301
## 7775 34 69 161 142 85
## 7857 65 33 170 138 95
## 7888 18 30 71 103 73
## 7924 37 111 266 140 26
## 7926 27 21 58 41 25
## 793 22 20 58 48 59
## 7980 279 1088 3643 2815 1112
## 8223 12 7 25 42 34
## 8232 229 1330 5125 5569 2071
## 8255 23 16 75 56 23
## 8258 86 116 118 87 74
## 8286 31 46 166 219 146
## 8289 215 218 988 2570 3752
## 8333 4577 8984 14189 9665 4070
## 8335 20 18 46 36 18
## 8542 27 23 25 9 5
## 881 122 221 358 272 159
## 8820 50 22 85 78 68
## 8848 174 292 841 1760 1227
## 8917 62 56 24 5 10
## 8961 161 192 312 455 621
## 8965 14 19 25 6 6
## 9301 8 20 51 16 11
## 9345 48 24 90 126 71
## 9391 48 59 62 23 9
## 9393 22 36 153 225 191
## 940 547 1382 5763 6499 4273
## 9470 44 53 113 59 42
## 9499 18 30 197 250 119
## 9560 14 15 40 29 25
## 9659 67 49 132 142 128
## 9732 13 9 21 35 21
## 9791 24 33 68 58 38
## 9860 96 98 78 20 16
## 9929 982 686 1866 3889 7295
## 9939 2438 5956 16801 15347 8233
## 9967 17 44 74 33 15